﻿namespace Pub.Class
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Mail;
    using System.Net.Mime;
    using System.Runtime.InteropServices;
    using System.Text;

    public class Email : Disposable
    {
        private readonly IEmail email;
        private string errorMessage;
        private readonly bool isSend;
        private readonly MailMessage message;
        private readonly SmtpClient smtpClient;

        public Email()
        {
            this.errorMessage = string.Empty;
            this.errorMessage = string.Empty;
            if (this.email.IsNull())
            {
                this.email = (IEmail) (WebConfig.GetApp("EmailProviderName") ?? "Pub.Class.Email.SmtpClient.SendEmail,Pub.Class.Email.SmtpClient").LoadClass();
                this.smtpClient = new SmtpClient();
                this.message = new MailMessage();
            }
        }

        public Email(string classNameAndAssembly)
        {
            this.errorMessage = string.Empty;
            this.errorMessage = string.Empty;
            if (this.email.IsNull())
            {
                this.email = (IEmail) classNameAndAssembly.IfNullOrEmpty("Pub.Class.Email.SmtpClient.SendEmail,Pub.Class.Email.SmtpClient").LoadClass();
                this.smtpClient = new SmtpClient();
                this.message = new MailMessage();
            }
        }

        public Email(string host, int port)
        {
            this.errorMessage = string.Empty;
            this.errorMessage = string.Empty;
            this.smtpClient = new SmtpClient(host, port);
            this.message = new MailMessage();
            this.isSend = true;
        }

        public Email(string dllFileName, string className)
        {
            this.errorMessage = string.Empty;
            this.errorMessage = string.Empty;
            if (this.email.IsNull())
            {
                this.email = (IEmail) dllFileName.LoadClass(className);
                this.smtpClient = new SmtpClient();
                this.message = new MailMessage();
            }
        }

        public virtual Email AddAttachment(string filePath)
        {
            Attachment item = new Attachment(filePath, "application/octet-stream");
            ContentDisposition contentDisposition = item.ContentDisposition;
            contentDisposition.CreationDate = System.IO.File.GetCreationTime(filePath);
            contentDisposition.ModificationDate = System.IO.File.GetLastWriteTime(filePath);
            contentDisposition.ReadDate = System.IO.File.GetLastAccessTime(filePath);
            this.Message.Attachments.Add(item);
            return this;
        }

        public virtual Email Bcc(Func<MailAddresses, MailAddresses> mailAddresses)
        {
            foreach (MailAddress address in mailAddresses(new MailAddresses()).AddressCollection)
            {
                this.Message.Bcc.Add(address);
            }
            return this;
        }

        public virtual Email Body(string body)
        {
            this.Message.Body = body;
            return this;
        }

        public virtual Email BodyEncoding(Encoding bodyEncoding)
        {
            this.Message.BodyEncoding = bodyEncoding;
            return this;
        }

        public virtual Email Cc(Func<MailAddresses, MailAddresses> mailAddresses)
        {
            foreach (MailAddress address in mailAddresses(new MailAddresses()).AddressCollection)
            {
                this.Message.CC.Add(address);
            }
            return this;
        }

        public virtual Email Clear()
        {
            this.ClearBcc();
            this.ClearCc();
            this.ClearTo();
            return this;
        }

        public virtual Email ClearBcc()
        {
            this.Message.Bcc.Clear();
            return this;
        }

        public virtual Email ClearCc()
        {
            this.Message.CC.Clear();
            return this;
        }

        public virtual Email ClearTo()
        {
            this.Message.To.Clear();
            return this;
        }

        public virtual Email Credentials(string username, string password)
        {
            if (username.IsNullEmpty() || password.IsNullEmpty())
            {
                this.UseDefaultCredentials(true);
            }
            else
            {
                this.smtpClient.Credentials = new NetworkCredential(username, password);
            }
            return this;
        }

        public virtual Email Credentials(string username, string password, string domain)
        {
            this.smtpClient.Credentials = new NetworkCredential(username, password, domain);
            return this;
        }

        public virtual Email From(string fromMail)
        {
            this.Message.From = new MailAddress(fromMail);
            return this;
        }

        public virtual Email From(string fromDisplayName, string fromMail)
        {
            this.Message.From = new MailAddress(fromMail, fromDisplayName);
            return this;
        }

        public virtual Email Host(string host)
        {
            this.smtpClient.Host = host;
            return this;
        }

        protected override void InternalDispose()
        {
            base.InternalDispose();
        }

        public virtual Email IsBodyHtml(bool isBodyHtml)
        {
            this.Message.IsBodyHtml = isBodyHtml;
            return this;
        }

        public virtual Email Port(int port)
        {
            this.smtpClient.Port = port;
            return this;
        }

        public bool Send()
        {
            this.errorMessage = string.Empty;
            if (this.isSend)
            {
                try
                {
                    this.smtpClient.Send(this.message);
                    return true;
                }
                catch (Exception exception)
                {
                    this.errorMessage = exception.ToExceptionDetail();
                    return false;
                }
            }
            bool flag = this.email.Send(this.message, this.smtpClient);
            if (!flag)
            {
                this.errorMessage = this.email.ErrorMessage;
            }
            return flag;
        }

        public virtual Email Server(string host, int port = 0x19)
        {
            this.smtpClient.Host = host;
            this.smtpClient.Port = port;
            return this;
        }

        public virtual Email Ssl(bool enableSsl)
        {
            this.smtpClient.EnableSsl = enableSsl;
            return this;
        }

        public virtual Email Subject(string subject)
        {
            this.Message.Subject = subject;
            return this;
        }

        public virtual Email SubjectEncoding(Encoding subjectEncoding)
        {
            this.Message.SubjectEncoding = subjectEncoding;
            return this;
        }

        public virtual Email To(Func<MailAddresses, MailAddresses> mailAddresses)
        {
            foreach (MailAddress address in mailAddresses(new MailAddresses()).AddressCollection)
            {
                this.Message.To.Add(address);
            }
            return this;
        }

        public virtual Email UseDefaultCredentials(bool useDefaultCredentials = true)
        {
            this.smtpClient.UseDefaultCredentials = useDefaultCredentials;
            return this;
        }

        public string ErrorMessage
        {
            get
            {
                return this.errorMessage;
            }
        }

        public MailMessage Message
        {
            get
            {
                return this.message;
            }
        }

        public class MailAddresses
        {
            private readonly MailAddressCollection addressCollection = new MailAddressCollection();

            public Email.MailAddresses Add(Dictionary<string, string> contacts)
            {
                foreach (KeyValuePair<string, string> pair in contacts)
                {
                    this.AddressCollection.Add(new MailAddress(pair.Value, pair.Key));
                }
                return this;
            }

            public Email.MailAddresses Add(IEnumerable<string> mails)
            {
                foreach (string str in mails)
                {
                    this.AddressCollection.Add(new MailAddress(str));
                }
                return this;
            }

            public Email.MailAddresses Add(string mail)
            {
                this.AddressCollection.Add(new MailAddress(mail));
                return this;
            }

            public Email.MailAddresses Add(string displayName, string mail)
            {
                this.AddressCollection.Add(new MailAddress(mail, displayName));
                return this;
            }

            internal MailAddressCollection AddressCollection
            {
                get
                {
                    return this.addressCollection;
                }
            }
        }
    }
}

